﻿using System;
using System.Text;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
using System.Diagnostics;
using Aliyun.OSS;
using Util.Extension;
using AntUnion.FrameWork.Util;

namespace AntUnion.FrameWork.Web.Common
{
    /// <summary>
    /// 公共逻辑操作类
    /// </summary>
    public static class CommonHelper
    {
        public static string CurrentPath = AppDomain.CurrentDomain.BaseDirectory;

        [DllImport("Decode.dll", EntryPoint = "Encode", ExactSpelling = true, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
        public static extern IntPtr Encode(IntPtr src);


        [DllImport("Decode.dll", EntryPoint = "Decode", ExactSpelling = true, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
        public static extern IntPtr Decode(IntPtr src);

        [DllImport("KeyGen.dll", EntryPoint = "GenerteCDKey", ExactSpelling = true, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
        public static extern IntPtr GenerteCDKey(int ip1, int ip2, int ip3);

        public static string EncodeStr(string src)
        {
            //CustomDLLInvoke dll = new CustomDLLInvoke(CurrentPath + @"bin\Decode.dll");
            //Encode compile = (Encode)dll.Invoke("Encode", typeof(Encode));
            return Marshal.PtrToStringAnsi(Encode(Marshal.StringToHGlobalAnsi(src)));
        }

        public static string DecodeStr(string src)
        {
            //CustomDLLInvoke dll = new CustomDLLInvoke(CurrentPath + @"bin\Decode.dll");
            //Decode compile = (Decode)dll.Invoke("Decode", typeof(Decode));
            return Marshal.PtrToStringAnsi(Decode(Marshal.StringToHGlobalAnsi(src)));
        }


        public static string KeyGenStr()
        {
            //CustomDLLInvoke dll = new CustomDLLInvoke(CurrentPath + @"bin\KeyGen.dll");
            //KeyGen compile = (KeyGen)dll.Invoke("GenerteCDKey", typeof(KeyGen));
            long unixtime = ToUnixTime(DateTimeUtil.Now);
            long ticks = DateTimeUtil.Now.Ticks;
            int p1 = int.Parse(unixtime.ToString().Substring((unixtime.ToString().Length - 5), 5));
            int p2 = int.Parse(ticks.ToString().Substring(ticks.ToString().Length - 6, 6));
            int p3 = DateTimeUtil.Now.Second;
            return Marshal.PtrToStringAnsi(GenerteCDKey(p1, p2, p3));

        }

        #region UnixTime DateTime
        /// <summary>
        /// DateTime时间格式转换为Unix时间戳格式
        /// </summary>
        /// <param name='dateTime'></param>
        /// <returns></returns>
        public static long ToUnixTime(DateTime dateTime)
        {
            long intResult = 0;
            DateTime startTime = TimeZoneInfo.ConvertTime(new System.DateTime(1970, 1, 1, 0, 0, 0, 0), TimeZoneInfo.Local);
            intResult = (int)(dateTime - startTime).TotalSeconds;
            return intResult;
        }

        /// <summary>
        /// Unix时间戳格式转换为DateTime时间格式
        /// </summary>
        /// <param name='unixtime'></param>
        /// <returns></returns>
        public static DateTime ToNormalTime(long unixtime)
        {
            DateTime time = DateTime.MinValue;
            DateTime startTime = TimeZoneInfo.ConvertTime(new System.DateTime(1970, 1, 1, 0, 0, 0, 0), TimeZoneInfo.Local);
            time = startTime.AddSeconds(unixtime);
            return time;
        }

        /// <summary>    
        /// Unix时间戳转为C#格式时间    
        /// </summary>    
        /// <param name="timeStamp">Unix时间戳格式,例如1482115779</param>    
        /// <returns>C#格式时间</returns>    
        public static DateTime GetTime(string timeStamp)
        {
            DateTime dtStart = TimeZoneInfo.ConvertTime(new DateTime(1970, 1, 1), TimeZoneInfo.Local);
            long lTime = long.Parse(timeStamp + "0000000");
            TimeSpan toNow = new TimeSpan(lTime);
            return dtStart.Add(toNow);
        }

        #endregion

        #region  根据日期获取该日期的周期信息

        /// <summary>
        /// 根据日期获取该日期的周期信息
        /// </summary>
        /// <param name="Date">日期（DateTime）</param>
        /// <param name="Split">分隔符（如：-）</param>
        /// <returns>返回：年+分隔符+第几周+分隔符+总周数，如（2010-52-52）</returns>
        public static string GetWeekOfDate(DateTime Date, string Split)
        {
            string strWeek = Get_Week_Of_Year(Date);
            strWeek = strWeek.Substring(0, 4) + Split + strWeek.Substring(4, 2) + Split +
                      GetWeekCountOfYear(Convert.ToInt32(strWeek.Substring(0, 4)));
            return strWeek;
        }

        /// <summary>
        /// 根据日期获取该日期的周期信息
        /// </summary>
        /// <param name="Date">日期（DateTime）</param>
        /// <returns>返回：第几周</returns>
        public static int GetWeekOfDate(DateTime Date)
        {
            return Convert.ToInt32(Get_Week_Of_Year(Date).Substring(4, 2));
        }

        /// <summary>
        ///   根据日期获取该日期的周期信息
        /// </summary>
        /// <param name="Date">日期（DateTime）</param>
        /// <returns>返回：年+第几周（如：201052）</returns>
        private static string Get_Week_Of_Year(DateTime Date)
        {
            string StrWeek = "";

            int Year = Date.Year;
            int weeks = 0;

            int Week = Convert.ToInt32(Date.DayOfWeek); //当前日期是一周当中的第几天：周日起算（0~6）
            int Week11 = Convert.ToInt32(Convert.ToDateTime(Date.Year.ToString() + "-" + "1-1").DayOfWeek);
            //当前年的1月1日是一周当中的第几天
            int Week1231 = Convert.ToInt32(Convert.ToDateTime(Date.Year.ToString() + "-" + "12-31").DayOfWeek);
            //当前年的12月31日是一周当中的第几天
            int Week01 = Convert.ToInt32(Convert.ToDateTime(((Date.Year) - 1).ToString() + "-" + "1-1").DayOfWeek);
            //上一年的1月1日是一周当中的第几天

            int days = Date.DayOfYear; //当前日期是当前年的第几天
            int daysoutoneweek = days - (7 - Week11);
            if (daysoutoneweek <= 0)
            {
                weeks = 1;
            }
            else
            {
                weeks = daysoutoneweek / 7;
                if (daysoutoneweek % 7 != 0)
                    weeks++;
                weeks++;
            }
            //以上到此获取到的是标准周

            //为满足中国习惯，改周一为一周的第一天
            if (Week == 0)
            {
                //Week == 0，说明正好是周日，那么获取到的周都要递减。
                weeks--;
            }

            //如果是第0周
            if (weeks == 0)
            {
                //那么就获取上一年12月31日的所在周
                weeks = GetWeekOfDate(Convert.ToDateTime(((Date.Year) - 1).ToString() + "-" + "12-31"));
                Year--;
            }
            else if (Date.Day < 7 && weeks == 1)
            {
                //判断当前年的第一周是否会被上一年最后一周合并，>3说明会被合并，那么就要改第一周为上年的最后一周
                if (Week11 > 4)
                {
                    //判断上一年的第一周是否会被上上一年最后一周合并，
                    if (Week01 > 4)
                    {
                        //>3说明会被合并，那么上一年就不会有53周，所以得到当前日期是上一年的第52周
                        weeks = 52;
                        Year--;
                    }
                    else
                    {
                        //<=3说明不会被合并，那么上一年就有53周，所以得到当前日期是上一年的第53周
                        weeks = 53;
                        Year--;
                    }
                }
            }
            //如果是53周
            else if (weeks == 53)
            {
                //判断当前年的12月31日是否会被下一年的第一周合并
                if (Week1231 <= 3)
                {
                    //<=3说明会被合并，由此判断当前年没有53周，所以得到当前日期是下一年的第一周
                    weeks = 1;
                    Year++;
                }
                //判断当前年的1月1日是否会被上一年的最后一周合并
                else if (Week11 > 4)
                {
                    //>3说明会被合并，由此判断当前年没有53周，所以得到当前日期是当前年的第52周
                    weeks = 52;
                }
                //如果以上条件都不符合，那么当前年肯定有53
                //else
                //{
                //    int nn = Get_Week_Of_Year(Convert.ToDateTime(Date.Year.ToString() + "-" + "1-1"));

                //    if (nn != 1)
                //    {
                //        weeks--;
                //    }
                //}
            }
            else
            {
                //如果不是一周的第一天，并且当前年的第一周会被上一年的最后一周合并，那么当前获取的周应该递减
                if (Week != 0 && Week11 > 4)
                    weeks--;
            }

            StrWeek = Year.ToString();
            if (weeks < 10)
            {
                StrWeek += '0';
            }
            StrWeek += weeks.ToString();

            return StrWeek;
        }

        /// <summary>
        /// 根据年份获取该年份的总周数
        /// </summary>
        /// <param name="Year">年份</param>
        /// <returns>返回：总周数</returns>
        public static int GetWeekCountOfYear(int Year)
        {
            int WeekCount = 52;

            int Week11 = Convert.ToInt32(Convert.ToDateTime(Year.ToString() + "-" + "1-1").DayOfWeek);
            //当前年的1月1日是一周当中的第几天
            int Week1231 = Convert.ToInt32(Convert.ToDateTime(Year.ToString() + "-" + "12-31").DayOfWeek);
            //当前年的12月31日是一周当中的第几天

            if (Week11 <= 4 && Week1231 > 3)
            {
                //只有在当前年的第一周和最后一周都不会被合并的情况下，该年才会有53周
                WeekCount = 53;
            }

            return WeekCount;
        }

        #endregion

        #region 加密相关

        /// <summary>
        /// MD5加密 
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string Md5(string str)
        {
            // Create a new instance of the MD5CryptoServiceProvider object. 
            MD5 md5Hasher = MD5.Create();
            // Convert the input string to a byte array and compute the hash. 
            byte[] data = md5Hasher.ComputeHash(Encoding.GetEncoding("UTF-8").GetBytes(str));
            return BitConverter.ToString(data).Replace("-", "").ToLower(); //可以直接使用这个方法 

        }

        public static string Sha1(string str)
        {
            SHA1 sha1Hasher = SHA1.Create();
            byte[] data = sha1Hasher.ComputeHash(Encoding.GetEncoding("UTF-8").GetBytes(str));
            return BitConverter.ToString(data).Replace("-", "").ToLower();
        }


        public static string EncryptPwd(string str)
        {
            return CommonHelper.Md5(CommonHelper.Sha1(str) + "3hz7kvnL0TdjNCZ1SasEKiJODmu6f4IUGY8cxlPw");
        }

        #endregion

        #region Stopwatch计时器
        /// <summary>
        /// 计时器开始
        /// </summary>
        /// <returns></returns>
        public static Stopwatch TimerStart()
        {
            Stopwatch watch = new Stopwatch();
            watch.Reset();
            watch.Start();
            return watch;
        }
        /// <summary>
        /// 计时器结束
        /// </summary>
        /// <param name="watch"></param>
        /// <returns></returns>
        public static string TimerEnd(Stopwatch watch)
        {
            watch.Stop();
            double costtime = watch.ElapsedMilliseconds;
            return costtime.ToString();
        }
        #endregion

        #region 自动生成日期编号
        /// <summary>
        /// 自动生成编号  201008251145409865
        /// </summary>
        /// <returns></returns>
        public static string CreateNo()
        {
            Random random = new Random();
            string strRandom = random.Next(1000, 10000).ToString(); //生成编号 
            string code = DateTimeUtil.Now.ToString("yyyyMMddHHmmss") + strRandom;//形如
            return code;
        }
        #endregion

        #region 自动生产时间戳编号
        public static string GetOrderNo(int cot = 5)
        {
            Random random = new Random();
            string strRandom = string.Empty; //生成编号 
            System.Random r = new Random();
            for (int i = 0; i < cot; i++)
            {
                strRandom += r.Next(0, 9);
            }

            string code = DateTimeUtil.GetTimeStamp().ToString() + strRandom;//形如
            return code;
        }
        #endregion

        #region 自动生产时间戳编号
        //判断长度是否大于等于4
        public static Boolean Check_N(int n)
        {
            if (n < 4) { return false; }
            else return true;
        }

        //判断字符串是否为空
        public static Boolean isNull_Char(string c)
        {
            if (c == null || "".Equals(c)) { return true; }
            else return false;
        }

        //生成密码
        public static string pass(int n, string c)
        {
            string str = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";    //62(1-10,11-36,37-62)
            string RStr, newpass;
            RStr = str + c;     //加上输入的字符串c
            int len = RStr.Length;
            char[] p = RStr.ToCharArray();      //转换为字符数组
            //随机生成密码
            if (Check_N(n) && !isNull_Char(c))
            {
                bool bdone = false;
                do
                {
                    newpass = "";
                    int count0 = 0, count1 = 0, count2 = 0, count3 = 0;
                    //生成长度为n的密码
                    for (int i = 0; i < n; i++)
                    {
                        int intR = new Random(Guid.NewGuid().GetHashCode()).Next(0, len);
                        //每次轮流加上一个随机字符
                        newpass = newpass + p[intR];

                        if (('0' <= p[intR]) && (p[intR] <= '9')) { count0++; }             //数字个数
                        else if (('a' <= p[intR]) && (p[intR] <= 'z')) { count1++; }        //小写个数
                        else if (('A' <= p[intR]) && (p[intR] <= 'Z')) { count2++; }        //大写个数
                        else count3++;      //字符个数
                    }

                    //判断是否每个都有包含
                    if (count0 * count1 * count2 * count3 == 0)
                        bdone = true;
                    else bdone = false;
                } while (bdone);    //没包含，重新获取
                return newpass;
            }
            else return "error string";
        }

        #endregion

        #region 删除最后一个字符之后的字符
        /// <summary>
        /// 删除最后结尾的一个逗号
        /// </summary>
        public static string DelLastComma(string str)
        {
            return str.Substring(0, str.LastIndexOf(","));
        }
        /// <summary>
        /// 删除最后结尾的指定字符后的字符
        /// </summary>
        public static string DelLastChar(string str, string strchar)
        {
            return str.Substring(0, str.LastIndexOf(strchar));
        }
        /// <summary>
        /// 删除最后结尾的长度
        /// </summary>
        /// <param name="str"></param>
        /// <param name="Length"></param>
        /// <returns></returns>
        public static string DelLastLength(string str, int Length)
        {
            if (string.IsNullOrEmpty(str))
                return "";
            str = str.Substring(0, str.Length - Length);
            return str;
        }
        #endregion

        #region 获取汉字首字母（可包含多个汉字）
        /// <summary>
        /// 获取汉字首字母（可包含多个汉字）
        /// </summary>
        /// <param name="strText"></param>
        /// <returns></returns>
        public static string GetChineseSpell(string strText)
        {
            int len = strText.Length;
            string myStr = "";
            for (int i = 0; i < len; i++)
            {
                myStr += getSpell(strText.Substring(i, 1));
            }
            return myStr;
        }

        public static string getSpell(string cnChar)
        {
            byte[] arrCN = Encoding.Default.GetBytes(cnChar);
            if (arrCN.Length > 1)
            {
                int area = (short)arrCN[0];
                int pos = (short)arrCN[1];
                int code = (area << 8) + pos;
                int[] areacode = { 45217, 45253, 45761, 46318, 46826, 47010, 47297, 47614, 48119, 48119, 49062, 49324, 49896, 50371, 50614, 50622, 50906, 51387, 51446, 52218, 52698, 52698, 52698, 52980, 53689, 54481 };
                for (int i = 0; i < 26; i++)
                {
                    int max = 55290;
                    if (i != 25) max = areacode[i + 1];
                    if (areacode[i] <= code && code < max)
                    {
                        return Encoding.Default.GetString(new byte[] { (byte)(65 + i) });
                    }
                }
                return "*";
            }
            else
                return cnChar;
        }

        /// <summary>
        /// 获取第一个汉字的首字母，只能输入汉字
        /// </summary>
        /// <param name="c"></param>
        /// <returns></returns>
        public static string GetPYChar(string c)
        {
            byte[] array = new byte[2];
            array = System.Text.Encoding.Default.GetBytes(c);
            int i = (short)(array[0] - '\0') * 256 + ((short)(array[1] - '\0'));
            if (i < 0xB0A1) return "*";
            if (i < 0xB0C5) return "A";
            if (i < 0xB2C1) return "B";
            if (i < 0xB4EE) return "C";
            if (i < 0xB6EA) return "D";
            if (i < 0xB7A2) return "E";
            if (i < 0xB8C1) return "F";
            if (i < 0xB9FE) return "G";
            if (i < 0xBBF7) return "H";
            if (i < 0xBFA6) return "J";
            if (i < 0xC0AC) return "K";
            if (i < 0xC2E8) return "L";
            if (i < 0xC4C3) return "M";
            if (i < 0xC5B6) return "N";
            if (i < 0xC5BE) return "O";
            if (i < 0xC6DA) return "P";
            if (i < 0xC8BB) return "Q";
            if (i < 0xC8F6) return "R";
            if (i < 0xCBFA) return "S";
            if (i < 0xCDDA) return "T";
            if (i < 0xCEF4) return "W";
            if (i < 0xD1B9) return "X";
            if (i < 0xD4D1) return "Y";
            if (i < 0xD7FA) return "Z";
            return "*";
        }
        #endregion

        #region 上传/删除 阿里云图片
        public static string UploadAliyunImg(string objectName, string objectPath)
        {
            string strurl = "";
            var endpoint = "";
            var accessKeyId = "";
            var accessKeySecret = "";
            var bucketName = "";//服务器文件夹名称

            // 创建OssClient实例。
            var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
            try
            {
                PutObjectResult putObject = client.PutObject(bucketName, objectName, objectPath);

                var req = new GeneratePresignedUriRequest(bucketName, objectName, SignHttpMethod.Get)
                {
                    Expiration = DateTimeUtil.Now.AddHours(24 * 365 * 100),
                };
                strurl = client.GeneratePresignedUri(req).OriginalString;
            }
            catch
            {
                strurl = "";
            }
            finally
            {
                if (System.IO.File.Exists(objectPath))//判断文件是否存在  
                {
                    System.IO.File.Delete(objectPath);//执行IO文件删除
                }
            }
            return strurl;
        }

        public static void DelAliyunImg(string objectName)
        {
            var endpoint = "";
            var accessKeyId = "";
            var accessKeySecret = "";
            var bucketName = "";//服务器文件夹名称

            var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
            try
            {
                client.DeleteObject(bucketName, objectName);
            }
            catch
            {
                //ErrorLog(ex.Message, "Works.Web.Common", "DelAliyunImg", "DJ");
            }
        }
        #endregion

        #region 截取字符串
        /// <summary>
        /// 截取字符串
        /// </summary>
        /// <param name="html"></param>
        /// <param name="lkey"></param>
        /// <param name="rkey"></param>
        /// <returns></returns>
        public static string GetSubKey(string html, string lkey, string rkey)
        {
            try
            {
                int l = html.IndexOf(lkey);
                int r = html.IndexOf(rkey, l + lkey.Length);
                return html.Substring(l + lkey.Length, r - l - lkey.Length);
            }
            catch
            {
                return "";
            }
        }
        #endregion

        #region 经纬度计算
        //地球半径，单位米
        private const double EARTH_RADIUS = 6378137;
        /// <summary>
        /// 计算两点位置的距离，返回两点的距离，单位 米
        /// 该公式为GOOGLE提供，误差小于0.2米
        /// </summary>
        /// <param name="lat1">第一点纬度</param>
        /// <param name="lng1">第一点经度</param>
        /// <param name="lat2">第二点纬度</param>
        /// <param name="lng2">第二点经度</param>
        /// <returns></returns>
        public static double GetDistance(string lat1_1, string lng1_1, string lat2_2, string lng2_2)
        {
            try
            {
                double lat1 = lat1_1.ToDouble();
                double lng1 = lng1_1.ToDouble();
                double lat2 = lat2_2.ToDouble();
                double lng2 = lng2_2.ToDouble();
                double radLat1 = Rad(lat1);
                double radLng1 = Rad(lng1);
                double radLat2 = Rad(lat2);
                double radLng2 = Rad(lng2);
                double a = radLat1 - radLat2;
                double b = radLng1 - radLng2;
                if (lat2 == 0 && lng2 == 0)
                    return -1;
                else
                {
                    double result = 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin(a / 2), 2) + Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Pow(Math.Sin(b / 2), 2))) * EARTH_RADIUS;
                    return Math.Round(result / 1000, 2, MidpointRounding.AwayFromZero);
                }
            }
            catch
            {
                return 0;
            }

        }
        /// <summary>
        /// 经纬度转化成弧度
        /// </summary>
        /// <param name="d"></param>
        /// <returns></returns>
        private static double Rad(double d)
        {
            return (double)d * Math.PI / 180d;
        }
        #endregion
    }


    public class CustomDLLInvoke
    {
        [DllImport("kernel32", EntryPoint = "LoadLibrary", SetLastError = true)]
        private extern static IntPtr LoadLibrary(string path);
        [DllImport("kernel32", EntryPoint = "GetProcAddress", SetLastError = true)]
        private extern static IntPtr GetProcAddress(IntPtr lib, String funcName);
        [DllImport("kernel32", EntryPoint = "FreeLibrary", SetLastError = true)]
        private extern static bool FreeLibrary(IntPtr lib);
        private IntPtr MLib;
        public CustomDLLInvoke(string dllPath)
        {
            MLib = LoadLibrary(dllPath);
        }
        ~CustomDLLInvoke()
        {
            FreeLibrary(MLib);
        }
        public Delegate Invoke(string APIName, Type t)
        {
            IntPtr api = GetProcAddress(MLib, APIName);
            return Marshal.GetDelegateForFunctionPointer(api, t);
        }

    }

}